﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Revit;
using YJKArchMethodLibrary.Utils;
using YJKFloor.Utility;
using TopologySearch;

namespace YJKFloor.FloorEditor
{
	public class FloorMergeEditor
	{
		public FloorMergeEditor(ExternalCommandData cmdData)
		{
			this.m_Revit = cmdData;
			this.m_Doc = this.m_Revit.Application.ActiveUIDocument.Document;
			this.m_FloorEditCommon = new FloorEditCommon(cmdData);
		}

		public Result Mearge(ref string msg)
		{
			List<Floor> list = new List<Floor>();
			if (!this.SelectFloors(ref list))
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			List<List<Floor>> list2 = new List<List<Floor>>();
			foreach (Floor floor in list)
			{
				bool flag = false;
				for (int i = 0; i < list2.Count; i++)
				{
					Floor floor2 = list2[i][0];
					if (this.IsSameAs(floor, floor2))
					{
						list2[i].Add(floor);
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					list2.Add(new List<Floor>
					{
						floor
					});
				}
			}
			bool flag2 = false;
			foreach (List<Floor> list3 in list2)
			{
				if (list3.Count >= 2)
				{
					this.MeargeFloors(list3);
					flag2 = true;
					foreach (Floor element in list3)
					{
						this.m_FloorEditCommon.DeleteElement(element);
					}
				}
			}
			if (!flag2)
			{
				msg = "无法合并楼板，请确认所选楼板是否连接、标高是否一致以及楼板类型是否相同。";
				return Autodesk.Revit.UI.Result.Failed;
			}
			MessageBox.Show("楼板合并成功。", "盈建科提示");
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private bool IsSameAs(Floor floor1, Floor floor2)
		{
			if (floor1.FloorType.Id.IntegerValue != floor2.FloorType.Id.IntegerValue)
			{
				return false;
			}
			ElementId elementId = floor1.get_Parameter(BuiltInParameter.LEVEL_PARAM).AsElementId();
			ElementId elementId2 = floor2.get_Parameter(BuiltInParameter.LEVEL_PARAM).AsElementId();
			if (elementId.IntegerValue != elementId2.IntegerValue)
			{
				return false;
			}
			double val = floor1.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).AsDouble();
			double val2 = floor2.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).AsDouble();
			if (!Geometry.IsEqual(val, val2))
			{
				return false;
			}
			double val3 = floor1.get_Parameter(BuiltInParameter.ROOF_SLOPE).AsDouble();
			double val4 = floor2.get_Parameter(BuiltInParameter.ROOF_SLOPE).AsDouble();
			return Geometry.IsEqual(val3, val4);
		}

		private bool SelectFloors(ref List<Floor> floors)
		{
			IList<Element> list = null;
			Selection selection = this.m_Revit.Application.ActiveUIDocument.Selection;
			try
			{
				list = selection.PickElementsByRectangle(new FloorFilter(), "框选要合并的楼板");
			}
			catch (Exception)
			{
				return false;
			}
			Document document = this.m_Revit.Application.ActiveUIDocument.Document;
			foreach (Element element in list)
			{
				Floor item = element as Floor;
				floors.Add(item);
			}
			return floors.Count > 0;
		}

		private List<Floor> MeargeFloors(List<Floor> floors)
		{
			FloorType floorType = null;
			Level level = null;
			double offset = 0.0;
			bool isStruct = false;
			this.m_FloorEditCommon.GetOldInfo(floors[0], ref floorType, ref level, ref offset, ref isStruct);
			List<Opening> list = new List<Opening>();
			List<Curve> list2 = new List<Curve>();
			List<Curve> list3 = new List<Curve>();
			foreach (Floor floor in floors)
			{
				List<Opening> openingByFloor = this.m_FloorEditCommon.GetOpeningByFloor(floor.Id);
				list.AddRange(openingByFloor);
				List<List<Curve>> list4 = new List<List<Curve>>();
				List<List<Curve>> list5 = new List<List<Curve>>();
				this.m_FloorEditCommon.GetFloorLoopAndOpeningLoop(floor, ref list4, ref list5);
				foreach (List<Curve> collection in list4)
				{
					list2.AddRange(collection);
				}
				foreach (List<Curve> collection2 in list5)
				{
					list3.AddRange(collection2);
				}
				foreach (Opening opening in openingByFloor)
				{
					foreach (object obj in opening.BoundaryCurves)
					{
						Curve item = (Curve)obj;
						list3.Add(item);
					}
				}
			}
			List<Floor> list6 = new List<Floor>();
			List<List<Curve>> list7 = this.MeargeLoop(list2);
			foreach (List<Curve> edgeLoop in list7)
			{
				Floor floor2 = this.m_FloorEditCommon.CreateFloor(edgeLoop, floorType, level, offset, isStruct);
				if (floor2 != null)
				{
					this.CopyParameters(floors[0], floor2);
					list6.Add(floor2);
				}
			}
			foreach (Opening element in list)
			{
				this.m_FloorEditCommon.DeleteElement(element);
			}
			List<List<Curve>> openingLoops = this.MeargeLoop(list3);
			this.m_FloorEditCommon.NewOpeing(openingLoops, list7, list6);
			return list6;
		}

		private void CopyParameters(Floor floorS, Floor floorD)
		{
			Transaction transaction = null;
			try
			{
				transaction = new Transaction(this.m_Doc);
				transaction.Start("copy parameters");
				ParameterSet parameters = floorS.Parameters;
				foreach (object obj in parameters)
				{
					Parameter parameter = (Parameter)obj;
					if (!parameter.IsReadOnly && !parameter.IsShared)
					{
						Definition definition = parameter.Definition;
						InternalDefinition internalDefinition = definition as InternalDefinition;
						if (internalDefinition != null && internalDefinition.Name.CompareTo("标记") != 0 && internalDefinition.Name.CompareTo("Number") != 0)
						{
							try
							{
                                switch ((int)parameter.StorageType)
								{
								case 1:
									floorD.GetParameter(internalDefinition.Name).Set(parameter.AsInteger());
									break;
								case 2:
									floorD.GetParameter(internalDefinition.Name).Set(parameter.AsDouble());
									break;
								case 3:
									floorD.GetParameter(internalDefinition.Name).Set(parameter.AsString());
									break;
								case 4:
									floorD.GetParameter(internalDefinition.Name).Set(parameter.AsElementId());
									break;
								}
							}
							catch (Exception)
							{
							}
						}
					}
				}
				transaction.Commit();
			}
			catch (Exception)
			{
				if (transaction != null)
				{
					transaction.RollBack();
				}
			}
		}

		private List<List<Curve>> MeargeLoop(List<Curve> loop)
		{
			List<Pole2D> list = new List<Pole2D>();
			foreach (Curve curve in loop)
			{
				Pole2D pole = Pole2D.TransformWallToStructure2DPole(curve, ElementId.InvalidElementId, 0.0, 0.0);
				int num = list.FindIndex((Pole2D value) => value.SameAs(pole));
				if (num == -1)
				{
					list.Add(pole);
				}
			}
			StructureLoopSearcher structureLoopSearcher = new StructureLoopSearcher(this.m_Revit);
			return structureLoopSearcher.GetFullFloorEdgeLoops(list, StructureLoopSearcher.SearchEdgeLocation.SEL_Outside);
		}

		private ExternalCommandData m_Revit;

		private Document m_Doc;

		private FloorEditCommon m_FloorEditCommon;
	}
}
